package at.ac.tuwien.dse.health.event.listener;

import at.ac.tuwien.dse.health.event.bus.EventBus;
import at.ac.tuwien.dse.health.event.bus.EventTarget;
import at.ac.tuwien.dse.health.event.type.Event;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;

import javax.annotation.PostConstruct;
import javax.jms.*;
import java.io.Serializable;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;

/**
 * Uses a {@link JmsTemplate} to send and receive {@link ObjectMessage ObjectMessages} containing {@link Event Events}.
 *
 * @author Bernhard Nickel
 * @author Gregor Schauer
 * @author Dominik Strasser
 */
public class JmsEventListener implements MessageListener, EventListener {
	private static final Logger LOGGER = LogManager.getLogger(JmsEventListener.class);
	JmsTemplate jmsTemplate;
	EventBus eventBus;

	/**
	 * Checks whether this {@link JmsEventListener} is initialized properly.
	 * <p/>
	 * At least one of the following conditions must be true:
	 * <ul>
	 * <li>{@code eventBus} is not {@code null}</li>
	 * <li>{@code jmsTemplate} is not {@code null}</li>
	 * </ul>
	 */
	@PostConstruct
	public void init() {
		checkState(jmsTemplate != null || eventBus != null, "Either 'eventBus' and/or 'jmsTemplate' must not be null.");
	}

	@Override
	public void handleEvent(EventTarget eventTarget, final Event<? extends Serializable> event) {
		checkState(jmsTemplate != null, "JmsTemplate not available. Please configure %s properly.", getClass());
		jmsTemplate.send(new MessageCreator() {
			@Override
			public Message createMessage(Session session) throws JMSException {
				return session.createObjectMessage(event);
			}
		});
	}

	@Override
	public void onMessage(Message message) {
		checkState(eventBus != null, "EventBus not available. Please configure %s properly.", getClass());
		checkArgument(message instanceof ObjectMessage, "Message must be of type ObjectMessage but was %s", message.getClass());

		ObjectMessage objectMessage = (ObjectMessage) message;
		try {
			Event<?> event = (Event<?>) objectMessage.getObject();
			eventBus.delegate(event);
		} catch (JMSException e) {
			LOGGER.catching(e);
		}
	}

	public void setJmsTemplate(JmsTemplate jmsTemplate) {
		this.jmsTemplate = jmsTemplate;
	}

	public void setEventBus(EventBus eventBus) {
		this.eventBus = eventBus;
	}
}
